﻿namespace Atomic.Mvc.ViewEngines
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Web;
    using System.Web.Compilation;
    using System.Web.Razor.Generator;
    using System.Web.WebPages.Razor;
    using Atomic.Extensions;
    using Atomic.Plugins;
    using Atomic.Plugins.Files;

    /// <summary>
    /// Razor 模板编译事件。
    /// </summary>
    public class RazorCompilationEvent : IRazorCompilationEvent
    {
        /// <summary>
        /// 插件管理器。
        /// </summary>
        private readonly IPluginManager _pluginManager = null;

        /// <summary>
        /// 程序集探测目录。
        /// </summary>
        private readonly IAssemblyProbingFolder _assemblyProbingFolder = null;

        /// <summary>
        /// 初始化 Razor 模板编译事件。
        /// </summary>
        public RazorCompilationEvent()
        {
            this._assemblyProbingFolder = AtomicContainer.Resolve<IAssemblyProbingFolder>();

            this._pluginManager = PluginManager.Current;
        }

        /// <summary>
        /// 代码编译开始后触发的事件。
        /// </summary>
        /// <param name="provider"></param>
        public void CodeGenerationStarted(RazorBuildProvider provider)
        {
            var pluginDescriptor = this.GetPluginDescriptor(provider.VirtualPath);

            if (pluginDescriptor != null)
            {
                var assembly = this._assemblyProbingFolder.LoadAssembly(pluginDescriptor.Dependency.Name);

                if (assembly != null)
                {
                    provider.AssemblyBuilder.AddAssemblyReference(assembly);
                }
            }
        }

        /// <summary>
        /// 代码编译后触发的事件。
        /// </summary>
        /// <param name="provider"></param>
        /// <param name="e"></param>
        public void CodeGenerationCompleted(RazorBuildProvider provider, CodeGenerationCompleteEventArgs e)
        {
        }

        /// <summary>
        /// 获得插件的依赖项。
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <returns></returns>
        private PluginDescriptor GetPluginDescriptor(string virtualPath)
        {
            var appRelativePath = VirtualPathUtility.ToAppRelative(virtualPath);
            var prefix = PrefixMatch(appRelativePath, new[] { "~/Plugins/", "~/Core/" });
            if (prefix == null)
                return null;

            var pluginId = PluginMatch(appRelativePath, prefix);
            if (pluginId == null)
                return null;

            return _pluginManager.AvailablePlugins().SingleOrDefault(plugin => plugin.Id == pluginId);
        }

        /// <summary>
        /// 匹配插件的名称。
        /// </summary>
        /// <param name="virtualPath">相对路径。</param>
        /// <param name="prefix">目录前缀。</param>
        /// <returns>插件名称。</returns>
        private static string PluginMatch(string virtualPath, string prefix)
        {
            var index = virtualPath.IndexOf('/', prefix.Length, virtualPath.Length - prefix.Length);
            if (index < 0)
                return null;

            var moduleName = virtualPath.Substring(prefix.Length, index - prefix.Length);
            return (string.IsNullOrEmpty(moduleName) ? null : moduleName);
        }

        /// <summary>
        /// 匹配相对路径的前缀，以确认是从指定目录开始。
        /// </summary>
        /// <param name="virtualPath">相对路径。</param>
        /// <param name="prefixes">目录列表。</param>
        /// <returns>返回满足条件的第一条目录。</returns>
        private static string PrefixMatch(string virtualPath, params string[] prefixes)
        {
            return prefixes.FirstOrDefault(p => virtualPath.StartsWith(p, StringComparison.OrdinalIgnoreCase));
        }
    }
}